/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javaapplication1;

import Interface.TelaPrincipal;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.JOptionPane;

/**
 *
 * @author Ceph
 */
public class Escalonador {
    private Processos[] vet = new Processos[50];
    private int cont=0;
    private Processador[] CPU;
    private FilaEntrada FE;
    private FilaProcesso FTR;
    private FilaUsuario FU;
    private FilaProcesso suspenso;
    private FilaProcesso pronto_suspenso;
    private Perifericos periferico;
    private int contador=0;
    private Object[] options = { "Avançar", "Parar" };
    
    public Escalonador(){
        CPU = new Processador[4];
        CPU[0] = new Processador();
        CPU[1] = new Processador(CPU[0].getMemoria());
        CPU[2] = new Processador();
        CPU[3] = new Processador(CPU[2].getMemoria());
        FE = new FilaEntrada();
        FTR = new FilaProcesso();
        FU = new FilaUsuario();
        suspenso = new FilaProcesso();
        pronto_suspenso = new FilaProcesso();
        periferico = new Perifericos();
    }

    public void lerEntrada() throws FileNotFoundException, IOException{
        BufferedReader in = new BufferedReader(new FileReader ("tst.txt"));
        String s;
        String[] s_vet;
        while ((s=in.readLine())!=null){
            s = s.replaceAll(" ","");
            s_vet= s.split(",");
            for (int i=0; i<8; i++){
                System.out.print(Integer.parseInt(s_vet[i]) + ", ");
            }
            System.out.println();

            vet[cont]= new Processos(Integer.parseInt(s_vet[0]),Integer.parseInt(s_vet[1]),Integer.parseInt(s_vet[2]),Integer.parseInt(s_vet[3]),Integer.parseInt(s_vet[4]),Integer.parseInt(s_vet[5]),Integer.parseInt(s_vet[6]),Integer.parseInt(s_vet[7]));
            cont++;
        }
    }
    
    public boolean verificaPerifericos(Processos processo){
        if (processo.getImpressoras()<=periferico.impLivre()){
            if (processo.getCds()<=periferico.cdLivre()){
                if ((processo.getModens()==0)|(periferico.mdLivre())){
                    if ((processo.getScanners()==0)|(periferico.scLivre())){
                        return(true);
                    }
                }
            }
        }
        return(false);
    }

    public Processador processadorLivre(Processos processo) throws Exception{
        if (processo!=null){
            for(int i=0; i<4;i++){
                if (CPU[i].livre()){
                    if (CPU[i].getMemoria().espaçoLivre(processo.getMb())){
                        return(CPU[i]);
                    }
                    else{
                        TelaPrincipal.getInstancia().escreverHistorico(" da CPU["+i+"].\n");
                    }
                }
            }
            if (processo.getPriority()==0){
                for(int i=0; i<4;i++){
                    if (!CPU[i].livre()){
                        if (CPU[i].getProcExecutando().getPriority()!=0){
                            suspende(CPU[i]);
                            return(CPU[i]);
                        }
                    }
                }
            }
        }
        return(null);
    }

    void suspende(Processador processador) throws Exception{
        Processos processo = processador.retira();
        processador.getMemoria().libera(processador.getProcExecutando());
        suspenso.add(processo);
        System.out.println("O "+processo.getNome()+" entrou da fila de suspenso.\n");
        periferico.recupera(processo);
    }

    public Processos proximoProcesso(){
        Processos proc;
        if (!FTR.vazia()){
            proc = FTR.head();
            return(proc);
        }
        else{
            if (!pronto_suspenso.vazia()){
                proc = pronto_suspenso.head();
                return (proc);
            }
        }
        proc = FU.head();
        return(proc);
    }

    public Processos getProximoProcesso() throws Exception{
        Processos proc;
        if (!FTR.vazia()){
            proc = FTR.remove();
            return(proc);
        }
        else{
            if (!pronto_suspenso.vazia()){
                proc = pronto_suspenso.remove();
                return (proc);
            }
        }
        proc = FU.remove();
        return(proc);
    }

    public void verificaQuantum() throws Exception{
        Processos processo;
        for (int i=0; i<4; i++){
            if (CPU[i].getProcExecutando()!=null){
                if (CPU[i].getProcExecutando().getPriority()!=0){
                    if (CPU[i].getTempoExecutando()==FU.getQuantum()){
                        processo = CPU[i].retira();
                        FU.add(processo);
                        TelaPrincipal.getInstancia().escreverHistorico("O "+processo.getNome()+" entrou da fila de usuário.\n");
                        periferico.recupera(processo);
                    }
                }
            }
        }
    }

    public void executa() throws Exception{
        Processos pr;
        for (int i = 0; i < 4; i++){
            CPU[i].processa();
            pr = CPU[i].getProcExecutando();
            if (CPU[i].acabou()){
                contador++;
                periferico.recupera(pr);
            }
        }
    }

    void imprime() throws Exception{
        //String retorno = "";
        if (CPU[0].getProcExecutando()!=null)
            TelaPrincipal.getInstancia().escreverCpu1(CPU[0].getProcExecutando().getNome());
        if (CPU[1].getProcExecutando()!=null)
            TelaPrincipal.getInstancia().escreverCpu2(CPU[1].getProcExecutando().getNome());
        if (CPU[2].getProcExecutando()!=null)
            TelaPrincipal.getInstancia().escreverCpu3(CPU[2].getProcExecutando().getNome());
        if (CPU[3].getProcExecutando()!=null)
            TelaPrincipal.getInstancia().escreverCpu4(CPU[3].getProcExecutando().getNome());
        TelaPrincipal.getInstancia().escreverFTR(imprimeFila(FTR));
        TelaPrincipal.getInstancia().escreverSU(imprimeFila(suspenso));
        TelaPrincipal.getInstancia().escreverPSU(imprimeFila(pronto_suspenso));
        TelaPrincipal.getInstancia().escreverFU0(imprimeFila(FU.getFila(0)));
        TelaPrincipal.getInstancia().escreverFU1(imprimeFila(FU.getFila(1)));
        TelaPrincipal.getInstancia().escreverFU2(imprimeFila(FU.getFila(2)));
    }

    String imprimeFila(FilaProcesso fila){
        return fila.imprime();
    }

    public void escalona() throws Exception {
        Processos processo=null;
        String resp;
        boolean parou = false;
        int tempo =0;
        while (contador < cont &&(!parou)){
            tempo++;
            resp = "Tempo: "+tempo+"\n";
            for(int i=0; i<cont;i++){
                if(vet[i].getArrivalTime()==tempo){
                    TelaPrincipal.getInstancia().escreverHistorico("Tempo: " + tempo + "s ");
                    FE.add(vet[i]);
                }
            }
            if (!suspenso.vazia()){
                if (verificaPerifericos(suspenso.head())){
                    pronto_suspenso.add(suspenso.remove());
                    TelaPrincipal.getInstancia().escreverPSU(imprimeFila(pronto_suspenso));
                }
            }
            if (tempo%5==0){
                while (!FE.vazia()){
                    Processos proc = FE.remove();
                    if (proc.getPriority() == 0){
                        FTR.add(proc); //adiciona FTR
                    }
                    else{
                        FU.add(proc);
                        TelaPrincipal.getInstancia().escreverHistorico("Tempo: " + tempo + "s ");
                        TelaPrincipal.getInstancia().escreverHistorico("O "+proc.getNome()+" entrou da fila de usuário.\n");
                    }
                }
            }
            if (processo==null){
                processo = proximoProcesso();
            }
            if (processo!=null){
                TelaPrincipal.getInstancia().escreverHistorico("O "+ processo.getNome() +" é o próximo processo.\n");
            }
            while ((processadorLivre(processo)!=null)){
                TelaPrincipal.getInstancia().escreverHistorico("Existe processador livre.\n");
                TelaPrincipal.getInstancia().escreverHistorico("Existe memória livre.\n");
                if (verificaPerifericos(processo)){
                    TelaPrincipal.getInstancia().escreverHistorico("Existe periférico livre.\n");
                    processadorLivre(processo).recebe(getProximoProcesso());
                    periferico.atende(processo);
                    processo = null;
                }
                else{
                    suspenso.add(getProximoProcesso());
                    TelaPrincipal.getInstancia().escreverSU(imprimeFila(suspenso));
                    processo = null;
                }
                processo = proximoProcesso();
                if (processo!=null){
                   TelaPrincipal.getInstancia().escreverHistorico("o "+ processo.getNome() +" é o próximo processo.\n");
                }
            }
            
            
            imprime();
            executa();
            verificaQuantum();
            if(TelaPrincipal.getInstancia().passo_a_passo){
                
                int i = JOptionPane.showConfirmDialog(null,"Deseja Avançar?", "Escalonador",
                JOptionPane.YES_NO_OPTION);
                if (i == JOptionPane.NO_OPTION) {
                    parou=true;
                    TelaPrincipal.getInstancia().iniciou=false;
                }
                
                
            }
        }
    }
}
